﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace pipeCore.Pipes.Units.NamedPortUnits.Units
{
    /// <summary>
    /// This interface will represent a unit that will send messages to other units
    /// </summary>
    public interface ISourceunit : INamedpipeunit
    {
        /// <summary>
        /// Send an object downstream, the implemented classes must override this implementation with a suitable implementation
        /// </summary>
        
        void Send();
        /// <summary>
        /// Hold A Collecation to all of the ports that will send messages
        /// </summary>
        Dictionary<String, pipeCore.Pipes.Ports.IPort> PortsOut { set; get; }
        /// <summary>
        /// Connect a specific pin on the unit to an othe rin the same unit or other unit
        /// </summary>
        /// <param name="pinSource">the source pin</param>
        /// <param name="PinSink">the sink pin</param>
        void Connect(String pinSource, String PinSink);
        /// <summary>
        /// Send a byte stream from specific port
        /// </summary>
        /// <param name="portname">port name</param>
        /// <param name="message">the message to send</param>
        void SendFrom(string portname, byte[] message);
    
    }
    
    /// <summary>
    ///  implements the Source unit any source unit must be drived from this class
    /// </summary>
    public abstract class SourceUnit : ISourceunit
    {
        /// <summary>
        /// Constract a new Source Unit
        /// </summary>
        public SourceUnit()
        {
            UnitName = "Source Unit";
        }
       
        /// <summary>
        /// Trigger all the outport to send 
        /// </summary>        
        public void Send()
        {
            string[] portname=PortsOut.Keys.ToArray();
            for (int i = 0; i < PortsOut.Keys.Count; i++) ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[portname[i]])).Send();
        }
        /// <summary>
        /// trigger the specified ports to send there data
        /// </summary>
        /// <param name="ports"></param>
        public void Send(String[] ports)
        {
            for (int i = 0; i < ports.Length; i++) ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[ports[i]])).Send();
        }
        /// <summary>
        /// Send a message from a specific port
        /// </summary>
        /// <param name="portName"></param>
        public void Send(String portName)
        {
            ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[portName])).Send();
        }

        /// <summary>
        /// The name of the unit
        /// </summary>

        public string UnitName
        {
            get;
            set;
        }

        /// <summary>
        /// Add port to the unit
        /// </summary>
        /// <param name="port"></param>
        public void Add(Ports.IPort port)
        {
            if (port.GetType() == typeof(pipeCore.Pipes.Units.NamedPortUnits.ports.Outport))
            {
                PortsOut.Add("port" + PortsOut.Count.ToString(), port);
                port.Name = PortsOut.Count.ToString();
            }
            else
            {
                throw new Exception("this Unit just except Outputports");
            }
        }
      /// <summary>
      /// Add a port to the unit
      /// </summary>
      /// <param name="port">port </param>
      /// <param name="Name">port name</param>
        public void Add(Ports.IPort port,String Name)
        {
            try
            {
                PortsOut.Add(Name, port);
                port.Name = Name;
            }
            catch (Exception err)
            {
                throw new Exception(err.Message);
            }
        
        }
        /// <summary>
        /// Create a new Outputport and add it to the port Collection
        /// </summary>
        /// <param name="portName">the port name</param>
        public void Add(String portName)
        {
            pipeCore.Pipes.Units.NamedPortUnits.ports.Outport port=new pipeCore.Pipes.Units.NamedPortUnits.ports.Outport(portName);
            Add(port, portName);
            
        }
        /// <summary>
        /// Collection of Outport ports
        /// </summary>
        public Dictionary<string, Ports.IPort> PortsOut
        {
            get;
            set;
        }
   
        /// <summary>
        /// Constract a new Source unit
        /// </summary>
        /// <param name="UnitName"></param>
        public SourceUnit(String UnitName)
        {
            this.UnitName = UnitName;
            PortsOut = new Dictionary<string, Ports.IPort>();
        }
        /// <summary>
        /// Connect a specific port to an other
        /// </summary>
        /// <param name="pinSource">from pin</param>
        /// <param name="PinSink">to pin </param>
        public void Connect(string pinSource, string PinSink)
        {
            ((pipeCore.Pipes.Ports.Ioutport)PortsOut[pinSource]).Connect(PinSink);
        }
        /// <summary>
        /// Send a message from a specific port
        /// </summary>
        /// <param name="p">the port to use </param>
        /// <param name="p_2">a message string</param>
        public void SendFrom(string p, string p_2)
        {
            byte[] msg=System.Text.ASCIIEncoding.ASCII.GetBytes(p_2);
            SendFrom(p, msg);
        }

        /// <summary>
        /// Send a message from a specific port
        /// </summary>
        /// <param name="portname">the port name</param>
        /// <param name="message">a byte arry of message</param>
        public void SendFrom(string portname, byte[] message)
        {
            ((pipeCore.Pipes.Ports.Ioutport)PortsOut[portname]).Data = message;
            ((pipeCore.Pipes.Ports.Ioutport)PortsOut[portname]).Send();
        }

        ISite site;
        /// <summary>
        /// inherited from IComponent
        /// </summary>
        public event EventHandler Disposed;
        /// <summary>
        /// Inherited from IComponent
        /// </summary>
        public System.ComponentModel.ISite Site
        {
            get
            {
               return site;
            }
            set
            {
                site=value;
            }
        }
        /// <summary>
        /// inherited from IComponent
        /// </summary>
        public void Dispose()
        {
             string[] portname = PortsOut.Keys.ToArray();
             for (int i = 0; i < PortsOut.Keys.Count; i++) 
                 ((pipeCore.Pipes.Ports.Ioutport)(PortsOut[portname[i]])).Dispose();
        }

        /// <summary>
        /// craeta new unit
        /// </summary>
        public virtual void Create()
        {
            PortsOut = new Dictionary<string, Ports.IPort>();
        }
    }



}
